package com.hanxiaozhang.threadbase1ndedition.no5juccommonclass;

import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;

/**
 * 〈一句话功能简述〉<br>
 * 〈Exchanger 交换器〉
 * <p>
 * 概念：
 * 用于两个工作线程之间交换数据。
 * -简单解释：一个线程在完成一定的事务后，想与另一个线程交换数据，则第一个先拿出数据的线程会一直等待第二个线程，直到第二个线程拿着数据到来时才能彼此交换对应数据。
 * <p>
 * 运行流程描述：
 * 当一个线程到达exchange调用点时，如果其他线程此前已经调用了此方法，则其他线程会被调度唤醒并与之进行对象交换，然后各自返回；
 * 如果其他线程还没到达交换点，则当前线程会被挂起，直至其他线程到达才会完成交换并正常返回，或者当前线程被中断或超时返回。
 * <p>
 * 常用方法：
 * exchange(V x)：等待另一个线程到达这个交换点（除非当前线程被中断），然后将给定的对象传输给该线程，并接收该线程的对象。
 * exchange(V x, long timeout, TimeUnit unit)：指定超时时间
 *
 * @author hanxinghua
 * @create 2021/11/14
 * @since 1.0.0
 */
public class No6Exchanger {


    private static Exchanger<String> stringExchanger = new Exchanger<>();


    public static void main(String[] args) throws InterruptedException {


        Exchanger<Integer> exchanger = new Exchanger<Integer>();
        new Producer("", exchanger).start();
        new Consumer("", exchanger).start();
        TimeUnit.SECONDS.sleep(7);

//        new Thread(() -> {
//            String s = "THREAD-1的数据";
//            try {
//                s = stringExchanger.exchange(s);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName() + "线程,交换得到" + s);
//
//        }, "THREAD-1").start();
//
//        new Thread(() -> {
//            String s = "THREAD-2的数据";
//            try {
//                s = stringExchanger.exchange(s);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            System.out.println(Thread.currentThread().getName() + "线程,交换得到" + s);
//
//        }, "THREAD-2").start();


    }


    /**
     * 生产者
     */
    static class Producer extends Thread {
        private Exchanger<Integer> exchanger;
        private static int data = 0;

        Producer(String name, Exchanger<Integer> exchanger) {
            super("Producer-" + name);
            this.exchanger = exchanger;
        }

        @Override
        public void run() {
            for (int i = 1; i < 5; i++) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                    data = i;
                    System.out.println(getName() + " 交换前:" + data);
                    data = exchanger.exchange(data);
                    System.out.println(getName() + " 交换后:" + data);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 消费者
     */
    static class Consumer extends Thread {
        private Exchanger<Integer> exchanger;
        private static int data = 0;

        Consumer(String name, Exchanger<Integer> exchanger) {
            super("Consumer-" + name);
            this.exchanger = exchanger;
        }

        @Override
        public void run() {
            while (true) {
                data = 0;
                System.out.println(getName() + " 交换前:" + data);
                try {
                    TimeUnit.SECONDS.sleep(1);
                    data = exchanger.exchange(data);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(getName() + " 交换后:" + data);
            }
        }
    }

}
